home *** CD-ROM | disk | FTP | other *** search
/ The Utilities Experience / The Utilities Experience - Volume 1.iso / software / misc / o-z / x-windows / mesa-amiwin / src / clip.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-30  |  28.1 KB  |  987 lines

  1. /* clip.c */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  1.2
  6.  * Copyright (C) 1995  Brian Paul  (brianp@ssec.wisc.edu)
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Library General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Library General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Library General Public
  19.  * License along with this library; if not, write to the Free
  20.  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23.  
  24. /*
  25.  * Functions for clipping points, lines, and polygons against the view
  26.  * volume and user-defined clipping planes.
  27.  */
  28.  
  29.  
  30. /*
  31. $Id: clip.c,v 1.14 1995/10/14 17:41:29 brianp Exp $
  32.  
  33. $Log: clip.c,v $
  34.  * Revision 1.14  1995/10/14  17:41:29  brianp
  35.  * made glClipPlane display list-able
  36.  *
  37.  * Revision 1.13  1995/09/15  18:54:09  brianp
  38.  * changed INSIDE, OUTSIDE macros to fix Oleg Krivosheev's clipping problems
  39.  *
  40.  * Revision 1.12  1995/07/28  21:32:12  brianp
  41.  * fixed aux data interpolation bug in gl_viewclip_line()
  42.  *
  43.  * Revision 1.11  1995/07/24  20:34:16  brianp
  44.  * replaced memset() with MEMSET() and memcpy() with MEMCPY()
  45.  *
  46.  * Revision 1.10  1995/07/14  16:11:26  brianp
  47.  * tests for divide by zero added to gl_userclip_line()
  48.  *
  49.  * Revision 1.9  1995/06/02  13:59:16  brianp
  50.  * changed MAX_VERTICES to VB_SIZE
  51.  *
  52.  * Revision 1.8  1995/05/22  21:02:41  brianp
  53.  * Release 1.2
  54.  *
  55.  * Revision 1.7  1995/05/12  19:24:13  brianp
  56.  * replaced CC.Mode!=0 with INSIDE_BEGIN_END
  57.  *
  58.  * Revision 1.6  1995/03/24  15:30:41  brianp
  59.  * introduced VB
  60.  *
  61.  * Revision 1.5  1995/03/09  21:41:03  brianp
  62.  * new ModelViewInv matrix logic
  63.  *
  64.  * Revision 1.4  1995/03/09  20:07:46  brianp
  65.  * changed order of arguments in gl_transform_vector
  66.  *
  67.  * Revision 1.3  1995/03/08  19:01:11  brianp
  68.  * removed extra #include "clip.h"
  69.  *
  70.  * Revision 1.2  1995/03/04  19:29:44  brianp
  71.  * 1.1 beta revision
  72.  *
  73.  * Revision 1.1  1995/02/24  14:18:09  brianp
  74.  * Initial revision
  75.  *
  76.  */
  77.  
  78.  
  79. #include <string.h>
  80. #include "GL/gl.h"
  81. #include "clip.h"
  82. #include "context.h"
  83. #include "list.h"
  84. #include "macros.h"
  85. #include "vb.h"
  86. #include "xform.h"
  87.  
  88.  
  89.  
  90.  
  91. /* Linear interpolation between A and B: */
  92. #define LINTERP( T, A, B )   ( (A) + (T) * ( (B) - (A) ) )
  93.  
  94.  
  95. #define EYE_SPACE 1
  96. #define CLIP_SPACE 2
  97.  
  98. static GLuint Space;
  99.  
  100.  
  101.  
  102. /*
  103.  * This function is used to interpolate colors, indexes, and texture
  104.  * coordinates when clipping has to be done.  In general, we compute
  105.  *     aux[dst] = aux[in] + t * (aux[out] - aux[in])
  106.  * where aux is the quantity to be interpolated.
  107.  * Input:  dst - index of array position to store interpolated value
  108.  *         t - a value in [0,1]
  109.  *         in - index of array position corresponding to 'inside' vertex
  110.  *         out - index of array position corresponding to 'outside' vertex
  111.  */
  112. static void interpolate_aux( GLuint dst, GLfloat t, GLuint in, GLuint out )
  113. {
  114.    if (CC.ClipMask & CLIP_FCOLOR_BIT) {
  115.       VB.Fcolor[dst][0] = LINTERP( t, VB.Fcolor[in][0], VB.Fcolor[out][0] );
  116.       VB.Fcolor[dst][1] = LINTERP( t, VB.Fcolor[in][1], VB.Fcolor[out][1] );
  117.       VB.Fcolor[dst][2] = LINTERP( t, VB.Fcolor[in][2], VB.Fcolor[out][2] );
  118.       VB.Fcolor[dst][3] = LINTERP( t, VB.Fcolor[in][3], VB.Fcolor[out][3] );
  119.    }
  120.    else if (CC.ClipMask & CLIP_FINDEX_BIT) {
  121.       VB.Findex[dst] = LINTERP( t, VB.Findex[in], VB.Findex[out] );
  122.    }
  123.  
  124.    if (CC.ClipMask & CLIP_BCOLOR_BIT) {
  125.       VB.Bcolor[dst][0] = LINTERP( t, VB.Bcolor[in][0], VB.Bcolor[out][0] );
  126.       VB.Bcolor[dst][1] = LINTERP( t, VB.Bcolor[in][1], VB.Bcolor[out][1] );
  127.       VB.Bcolor[dst][2] = LINTERP( t, VB.Bcolor[in][2], VB.Bcolor[out][2] );
  128.       VB.Bcolor[dst][3] = LINTERP( t, VB.Bcolor[in][3], VB.Bcolor[out][3] );
  129.    }
  130.    else if (CC.ClipMask & CLIP_BINDEX_BIT) {
  131.       VB.Bindex[dst] = LINTERP( t, VB.Bindex[in], VB.Bindex[out] );
  132.    }
  133.  
  134.    if (CC.ClipMask & CLIP_TEXTURE_BIT) {
  135.       /* TODO: is more sophisticated texture coord interpolation needed?? */
  136.       if (Space==CLIP_SPACE) {
  137.      /* also interpolate eye Z component */
  138.      VB.Eye[dst][2] = LINTERP( t, VB.Eye[in][2], VB.Eye[out][2] );
  139.       }
  140.       VB.TexCoord[dst][0] = LINTERP(t,VB.TexCoord[in][0],VB.TexCoord[out][0]);
  141.       VB.TexCoord[dst][1] = LINTERP(t,VB.TexCoord[in][1],VB.TexCoord[out][1]);
  142.    }
  143.  
  144. }
  145.  
  146.  
  147.  
  148.  
  149. void gl_clipplane( GLenum plane, const float *equation )
  150. {
  151.    GLint p;
  152.  
  153.    p = (GLint) (plane - GL_CLIP_PLANE0);
  154.    if (p<0 || p>=MAX_CLIP_PLANES) {
  155.       gl_error( GL_INVALID_ENUM, "glClipPlane" );
  156.       return;
  157.    }
  158.  
  159.    /*
  160.     * The Equation is transformed by the transpose of the inverse of the
  161.     * current modelview matrix and stored in the resulting eye coordinates.
  162.     */
  163.    if (!CC.ModelViewInvValid) {
  164.       gl_compute_modelview_inverse();
  165.    }
  166.    gl_transform_vector( CC.Transform.ClipEquation[p], equation,
  167.                 CC.ModelViewInv );
  168. }
  169.  
  170.  
  171.  
  172. void glClipPlane( GLenum plane, const GLdouble *equation )
  173. {
  174.    GLfloat fequation[4];
  175.    fequation[0] = (GLfloat) equation[0];
  176.    fequation[1] = (GLfloat) equation[1];
  177.    fequation[2] = (GLfloat) equation[2];
  178.    fequation[3] = (GLfloat) equation[3];
  179.    if (CC.CompileFlag) {
  180.       gl_save_clipplane( plane, fequation );
  181.    }
  182.    if (CC.ExecuteFlag) {
  183.       gl_clipplane( plane, fequation );
  184.    }
  185. }
  186.  
  187.  
  188.  
  189. void glGetClipPlane( GLenum plane, GLdouble *equation )
  190. {
  191.    GLint p;
  192.  
  193.    if (INSIDE_BEGIN_END) {
  194.       gl_error( GL_INVALID_OPERATION, "glGetClipPlane" );
  195.       return;
  196.    }
  197.  
  198.    p = (GLint) (plane - GL_CLIP_PLANE0);
  199.    if (p<0 || p>=MAX_CLIP_PLANES) {
  200.       gl_error( GL_INVALID_ENUM, "glGetClipPlane" );
  201.       return;
  202.    }
  203.  
  204.    equation[0] = (GLdouble) CC.Transform.ClipEquation[p][0];
  205.    equation[1] = (GLdouble) CC.Transform.ClipEquation[p][1];
  206.    equation[2] = (GLdouble) CC.Transform.ClipEquation[p][2];
  207.    equation[3] = (GLdouble) CC.Transform.ClipEquation[p][3];
  208. }
  209.  
  210.  
  211.  
  212.  
  213. /**********************************************************************/
  214. /*                         View volume clipping.                      */
  215. /**********************************************************************/
  216.  
  217.  
  218. /*
  219.  * Clip a point against the view volume.
  220.  * Input:  v - vertex-vector describing the point to clip
  221.  * Return:  0 = outside view volume
  222.  *          1 = inside view volume
  223.  */
  224. GLuint gl_viewclip_point( const GLfloat v[] )
  225. {
  226.    if (   v[0] > v[3] || v[0] < -v[3]
  227.        || v[1] > v[3] || v[1] < -v[3]
  228.        || v[2] > v[3] || v[2] < -v[3] ) {
  229.       return 0;
  230.    }
  231.    else {
  232.       return 1;
  233.    }
  234. }
  235.  
  236.  
  237.  
  238.  
  239. /*
  240.  * Clip a line segment against the view volume defined by -w<=x,y,z<=w.
  241.  * Input:  i, j - indexes into VB.V* of endpoints of the line
  242.  * Return:  0 = line completely outside of view
  243.  *          1 = line is inside view.
  244.  */
  245. GLuint gl_viewclip_line( GLuint *i, GLuint *j )
  246. {
  247.    GLfloat t, dx, dy, dz, dw;
  248.    register GLuint ii, jj;
  249.  
  250.    Space = CLIP_SPACE;
  251.    ii = *i;
  252.    jj = *j;
  253.  
  254. /*
  255.  * We use 6 instances of this code to clip agains the 6 planes.
  256.  * For each plane, we define the OUTSIDE and COMPUTE_INTERSECTION
  257.  * macros apprpriately.
  258.  */
  259. #define GENERAL_CLIP                            \
  260.    if (OUTSIDE(ii)) {                                           \
  261.       if (OUTSIDE(jj)) {                                        \
  262.          /* both verts are outside ==> return 0 */            \
  263.          return 0;                                              \
  264.       }                                                         \
  265.       else {                                                    \
  266.          /* ii is outside, jj is inside ==> clip */             \
  267.      /* new vertex put in position VB.Free */            \
  268.          COMPUTE_INTERSECTION( VB.Free, jj, ii )                     \
  269.      if (CC.ClipMask)  interpolate_aux( VB.Free, t, jj, ii );    \
  270.      ii = VB.Free;                            \
  271.      VB.Free++;                            \
  272.      if (VB.Free==VB_SIZE)  VB.Free = 1;                \
  273.       }                                                         \
  274.    }                                                            \
  275.    else {                                                       \
  276.       if (OUTSIDE(jj)) {                                        \
  277.          /* ii is inside, jj is outside ==> clip */             \
  278.      /* new vertex put in position VB.Free */            \
  279.          COMPUTE_INTERSECTION( VB.Free, ii, jj );                    \
  280.      if (CC.ClipMask)  interpolate_aux( VB.Free, t, ii, jj );    \
  281.      jj = VB.Free;                            \
  282.      VB.Free++;                            \
  283.      if (VB.Free==VB_SIZE)  VB.Free = 1;                \
  284.       }                                                         \
  285.       /* else both verts are inside ==> do nothing */           \
  286.    }
  287.  
  288.  
  289. #define X(I)    VB.Clip[I][0]
  290. #define Y(I)    VB.Clip[I][1]
  291. #define Z(I)    VB.Clip[I][2]
  292. #define W(I)    VB.Clip[I][3]
  293.  
  294. /*
  295.  * Begin clipping
  296.  */
  297.  
  298.    /*** Clip against +X side ***/
  299. #define OUTSIDE(K)      (X(K) > W(K))
  300. #define COMPUTE_INTERSECTION( new, in, out )        \
  301.     dx = X(out) - X(in);                \
  302.     dw = W(out) - W(in);                \
  303.     t = (X(in) - W(in)) / (dw-dx);            \
  304.     X(new) = X(in) + t * dx;            \
  305.     Y(new) = Y(in) + t * (Y(out) - Y(in));        \
  306.     Z(new) = Z(in) + t * (Z(out) - Z(in));        \
  307.     W(new) = W(in) + t * dw;
  308.  
  309.    GENERAL_CLIP
  310.  
  311. #undef OUTSIDE
  312. #undef COMPUTE_INTERSECTION
  313.  
  314.  
  315.    /*** Clip against -X side ***/
  316. #define OUTSIDE(K)      (X(K) < -W(K))
  317. #define COMPUTE_INTERSECTION( new, in, out )        \
  318.     dx = X(out) - X(in);                \
  319.     dw = W(out) - W(in);                \
  320.         t = -(X(in) + W(in)) / (dw+dx);            \
  321.     X(new) = X(in) + t * dx;            \
  322.     Y(new) = Y(in) + t * (Y(out) - Y(in));        \
  323.     Z(new) = Z(in) + t * (Z(out) - Z(in));        \
  324.     W(new) = W(in) + t * dw;
  325.  
  326.    GENERAL_CLIP
  327.  
  328. #undef OUTSIDE
  329. #undef COMPUTE_INTERSECTION
  330.  
  331.  
  332.    /*** Clip against +Y side ***/
  333. #define OUTSIDE(K)      (Y(K) > W(K))
  334. #define COMPUTE_INTERSECTION( new, in, out )        \
  335.     dy = Y(out) - Y(in);                \
  336.     dw = W(out) - W(in);                \
  337.         t = (Y(in) - W(in)) / (dw-dy);            \
  338.     X(new) = X(in) + t * (X(out) - X(in));        \
  339.     Y(new) = Y(in) + t * dy;            \
  340.     Z(new) = Z(in) + t * (Z(out) - Z(in));        \
  341.     W(new) = W(in) + t * dw;
  342.  
  343.    GENERAL_CLIP
  344.  
  345. #undef OUTSIDE
  346. #undef COMPUTE_INTERSECTION
  347.  
  348.  
  349.    /*** Clip against -Y side ***/
  350. #define OUTSIDE(K)      (Y(K) < -W(K))
  351. #define COMPUTE_INTERSECTION( new, in, out )        \
  352.         dy = Y(out) - Y(in);                \
  353.         dw = W(out) - W(in);                \
  354.         t = -(Y(in) + W(in)) / (dw+dy);            \
  355.         X(new) = X(in) + t * (X(out) - X(in));        \
  356.     Y(new) = Y(in) + t * dy;            \
  357.     Z(new) = Z(in) + t * (Z(out) - Z(in));        \
  358.     W(new) = W(in) + t * dw;
  359.  
  360.    GENERAL_CLIP
  361.  
  362. #undef OUTSIDE
  363. #undef COMPUTE_INTERSECTION
  364.  
  365.  
  366.    /*** Clip against +Z side ***/
  367. #define OUTSIDE(K)      (Z(K) > W(K))
  368. #define COMPUTE_INTERSECTION( new, in, out )        \
  369.         dz = Z(out) - Z(in);                \
  370.         dw = W(out) - W(in);                \
  371.         t = (Z(in) - W(in)) / (dw-dz);            \
  372.         X(new) = X(in) + t * (X(out) - X(in));        \
  373.         Y(new) = Y(in) + t * (Y(out) - Y(in));        \
  374.     Z(new) = Z(in) + t * dz;            \
  375.     W(new) = W(in) + t * dw;
  376.  
  377.    GENERAL_CLIP
  378.  
  379. #undef OUTSIDE
  380. #undef COMPUTE_INTERSECTION
  381.  
  382.  
  383.    /*** Clip against -Z side ***/
  384. #define OUTSIDE(K)      (Z(K) < -W(K))
  385. #define COMPUTE_INTERSECTION( new, in, out )        \
  386.         dz = Z(out) - Z(in);                \
  387.         dw = W(out) - W(in);                \
  388.         t = -(Z(in) + W(in)) / (dw+dz);            \
  389.         X(new) = X(in) + t * (X(out) - X(in));        \
  390.         Y(new) = Y(in) + t * (Y(out) - Y(in));        \
  391.     Z(new) = Z(in) + t * dz;            \
  392.     W(new) = W(in) + t * dw;
  393.  
  394.    GENERAL_CLIP
  395.  
  396. #undef OUTSIDE
  397. #undef COMPUTE_INTERSECTION
  398.  
  399. #undef GENERAL_CLIP
  400.  
  401.    *i = ii;
  402.    *j = jj;
  403.    return 1;
  404. }
  405.  
  406.  
  407.  
  408.  
  409. /*
  410.  * Clip a polygon against the view volume defined by -w<=x,y,z<=w.
  411.  * Input:  n - number of vertices in input polygon.
  412.  *         vlist - list of indexes into VB.V* of polygon to clip.
  413.  * Output:  vlist - modified list of vertex indexes
  414.  * Return:  number of vertices in resulting polygon
  415.  */
  416. GLuint gl_viewclip_polygon( GLuint n, GLuint vlist[] )
  417.  
  418. {
  419.    GLuint previ, prevj;
  420.    GLuint curri, currj;
  421.    GLuint vlist2[VB_MAX];
  422.    GLuint n2;
  423.    GLfloat dx, dy, dz, dw, t;
  424.    GLuint incount, i;
  425.  
  426.    Space = CLIP_SPACE;
  427.  
  428.    /* Trivial inside clipping test. */
  429.    incount = 0;
  430.    for (i=0;i<n;i++) {
  431.       GLuint j = vlist[i];
  432.       GLfloat vi3 = VB.Clip[j][3];
  433.       if (VB.Clip[j][0] <= vi3 && VB.Clip[j][0] >= -vi3 &&
  434.       VB.Clip[j][1] <= vi3 && VB.Clip[j][1] >= -vi3 &&
  435.       VB.Clip[j][2] <= vi3 && VB.Clip[j][2] >= -vi3) {
  436.      incount++;
  437.       }
  438.    }
  439.    if (incount==n) {
  440.       return n;
  441.    }
  442.  
  443.  
  444. /*
  445.  * We use 6 instances of this code to implement clipping against the
  446.  * 6 sides of the view volume.  Prior to each we define the macros:
  447.  *    INLIST = array which lists input vertices
  448.  *    OUTLIST = array which lists output vertices
  449.  *    INCOUNT = variable which is the number of vertices in INLIST[]
  450.  *    OUTCOUNT = variable which is the number of vertices in OUTLIST[]
  451.  *    INSIDE(J) = test if vertex[J] is inside the view volume
  452.  *    COMPUTE_INTERSECTION(inv,outv,newv) = compute intersection of line
  453.  *              from inv[] to outv[] with the clipping plane and store
  454.  *              the result in newv[]
  455.  */
  456.  
  457. #define GENERAL_CLIP                                                    \
  458.    if (INCOUNT<3)  return 0;                        \
  459.    previ = INCOUNT-1;        /* let previous = last vertex */    \
  460.    prevj = INLIST[previ];                        \
  461.    OUTCOUNT = 0;                                                        \
  462.    for (curri=0;curri<INCOUNT;curri++) {                \
  463.       currj = INLIST[curri];                        \
  464.       if (INSIDE(currj)) {                        \
  465.          if (INSIDE(prevj)) {                        \
  466.             /* both verts are inside ==> copy current to outlist */     \
  467.         OUTLIST[OUTCOUNT] = currj;                    \
  468.         OUTCOUNT++;                            \
  469.          }                                                              \
  470.          else {                                                         \
  471.             /* current is inside and previous is outside ==> clip */    \
  472.         COMPUTE_INTERSECTION( VB.Clip[currj], VB.Clip[prevj],    \
  473.                      VB.Clip[VB.Free] )        \
  474.         /* interpolate aux info using the value of t */        \
  475.         if (CC.ClipMask)  interpolate_aux( VB.Free, t, currj, prevj ); \
  476.         VB.Edgeflag[VB.Free] = VB.Edgeflag[prevj];        \
  477.         OUTLIST[OUTCOUNT] = VB.Free;                \
  478.         VB.Free++;                            \
  479.         if (VB.Free==VB_SIZE)   VB.Free = 1;            \
  480.         OUTCOUNT++;                            \
  481.         /* Output current */                    \
  482.         OUTLIST[OUTCOUNT] = currj;                    \
  483.         OUTCOUNT++;                            \
  484.          }                                                              \
  485.       }                                                                 \
  486.       else {                                                            \
  487.          if (INSIDE(prevj)) {                                           \
  488.             /* current is outside and previous is inside ==> clip */    \
  489.         COMPUTE_INTERSECTION( VB.Clip[prevj], VB.Clip[currj],    \
  490.                     VB.Clip[VB.Free] )        \
  491.         /* interpolate aux info using the value of t */        \
  492.         if (CC.ClipMask)  interpolate_aux( VB.Free, t, prevj, currj ); \
  493.         VB.Edgeflag[VB.Free] = VB.Edgeflag[prevj];        \
  494.         OUTLIST[OUTCOUNT] = VB.Free;                \
  495.         VB.Free++;                            \
  496.         if (VB.Free==VB_SIZE)   VB.Free = 1;            \
  497.         OUTCOUNT++;                            \
  498.          }                                                              \
  499.          /* else both verts are outside ==> do nothing */               \
  500.       }                                                                 \
  501.       /* let previous = current */                    \
  502.       previ = curri;                            \
  503.       prevj = currj;                            \
  504.    }
  505.  
  506.  
  507. /*
  508.  * Clip against +X
  509.  */
  510. #define INCOUNT n
  511. #define OUTCOUNT n2
  512. #define INLIST vlist
  513. #define OUTLIST vlist2
  514. #define INSIDE(J)      ( VB.Clip[J][0] <= VB.Clip[J][3] )
  515.  
  516. #define COMPUTE_INTERSECTION( inv, outv, newv )        \
  517.         dx = outv[0] - inv[0];                \
  518.         dw = outv[3] - inv[3];                \
  519.         t = (inv[0]-inv[3]) / (dw-dx);            \
  520.     newv[0] = inv[0] + t * dx;            \
  521.     newv[1] = inv[1] + t * (outv[1]-inv[1]);    \
  522.     newv[2] = inv[2] + t * (outv[2]-inv[2]);     \
  523.     newv[3] = inv[3] + t * dw;
  524.  
  525.    GENERAL_CLIP
  526.  
  527. #undef INCOUNT
  528. #undef OUTCOUNT
  529. #undef INLIST
  530. #undef OUTLIST
  531. #undef INSIDE
  532. #undef COMPUTE_INTERSECTION
  533.  
  534.  
  535. /*
  536.  * Clip against -X
  537.  */
  538. #define INCOUNT n2
  539. #define OUTCOUNT n
  540. #define INLIST vlist2
  541. #define OUTLIST vlist
  542. #define INSIDE(J)       (VB.Clip[J][0] >= -VB.Clip[J][3])
  543.  
  544. #define COMPUTE_INTERSECTION( inv, outv, newv )        \
  545.         dx = outv[0]-inv[0];                          \
  546.         dw = outv[3]-inv[3];                          \
  547.         t = -(inv[0]+inv[3]) / (dw+dx);               \
  548.         newv[0] = inv[0] + t * dx;                    \
  549.         newv[1] = inv[1] + t * (outv[1]-inv[1]);    \
  550.         newv[2] = inv[2] + t * (outv[2]-inv[2]);    \
  551.         newv[3] = inv[3] + t * dw;
  552.  
  553.    GENERAL_CLIP
  554.  
  555. #undef INCOUNT
  556. #undef OUTCOUNT
  557. #undef INLIST
  558. #undef OUTLIST
  559. #undef INSIDE
  560. #undef COMPUTE_INTERSECTION
  561.  
  562.  
  563. /*
  564.  * Clip against +Y
  565.  */
  566. #define INCOUNT n
  567. #define OUTCOUNT n2
  568. #define INLIST vlist
  569. #define OUTLIST vlist2
  570. #define INSIDE(J)       (VB.Clip[J][1] <= VB.Clip[J][3])
  571. #define COMPUTE_INTERSECTION( inv, outv, newv )        \
  572.         dy = outv[1]-inv[1];                          \
  573.         dw = outv[3]-inv[3];                          \
  574.         t = (inv[1]-inv[3]) / (dw-dy);                \
  575.         newv[0] = inv[0] + t * (outv[0]-inv[0]);    \
  576.         newv[1] = inv[1] + t * dy;            \
  577.         newv[2] = inv[2] + t * (outv[2]-inv[2]);    \
  578.         newv[3] = inv[3] + t * dw;
  579.  
  580.    GENERAL_CLIP
  581.  
  582. #undef INCOUNT
  583. #undef OUTCOUNT
  584. #undef INLIST
  585. #undef OUTLIST
  586. #undef INSIDE
  587. #undef COMPUTE_INTERSECTION
  588.  
  589.  
  590. /*
  591.  * Clip against -Y
  592.  */
  593. #define INCOUNT n2
  594. #define OUTCOUNT n
  595. #define INLIST vlist2
  596. #define OUTLIST vlist
  597. #define INSIDE(J)       (VB.Clip[J][1] >= -VB.Clip[J][3])
  598. #define COMPUTE_INTERSECTION( inv, outv, newv )        \
  599.         dy = outv[1]-inv[1];                          \
  600.         dw = outv[3]-inv[3];                          \
  601.         t = -(inv[1]+inv[3]) / (dw+dy);               \
  602.         newv[0] = inv[0] + t * (outv[0]-inv[0]);    \
  603.         newv[1] = inv[1] + t * dy;                    \
  604.         newv[2] = inv[2] + t * (outv[2]-inv[2]);    \
  605.         newv[3] = inv[3] + t * dw;
  606.  
  607.    GENERAL_CLIP
  608.  
  609. #undef INCOUNT
  610. #undef OUTCOUNT
  611. #undef INLIST
  612. #undef OUTLIST
  613. #undef INSIDE
  614. #undef COMPUTE_INTERSECTION
  615.  
  616.  
  617.  
  618. /*
  619.  * Clip against +Z
  620.  */
  621. #define INCOUNT n
  622. #define OUTCOUNT n2
  623. #define INLIST vlist
  624. #define OUTLIST vlist2
  625. #define INSIDE(J)       (VB.Clip[J][2] <= VB.Clip[J][3])
  626. #define COMPUTE_INTERSECTION( inv, outv, newv )        \
  627.         dz = outv[2]-inv[2];                          \
  628.         dw = outv[3]-inv[3];                          \
  629.         t = (inv[2]-inv[3]) / (dw-dz);                \
  630.         newv[0] = inv[0] + t * (outv[0]-inv[0]);    \
  631.         newv[1] = inv[1] + t * (outv[1]-inv[1]);    \
  632.         newv[2] = inv[2] + t * dz;                    \
  633.         newv[3] = inv[3] + t * dw;
  634.  
  635.    GENERAL_CLIP
  636.  
  637. #undef INCOUNT
  638. #undef OUTCOUNT
  639. #undef INLIST
  640. #undef OUTLIST
  641. #undef INSIDE
  642. #undef COMPUTE_INTERSECTION
  643.  
  644.  
  645. /*
  646.  * Clip against -Z
  647.  */
  648. #define INCOUNT n2
  649. #define OUTCOUNT n
  650. #define INLIST vlist2
  651. #define OUTLIST vlist
  652. #define INSIDE(J)       (VB.Clip[J][2] >= -VB.Clip[J][3])
  653. #define COMPUTE_INTERSECTION( inv, outv, newv )        \
  654.         dz = outv[2]-inv[2];                          \
  655.         dw = outv[3]-inv[3];                          \
  656.         t = -(inv[2]+inv[3]) / (dw+dz);               \
  657.         newv[0] = inv[0] + t * (outv[0]-inv[0]);    \
  658.         newv[1] = inv[1] + t * (outv[1]-inv[1]);    \
  659.         newv[2] = inv[2] + t * dz;                    \
  660.         newv[3] = inv[3] + t * dw;
  661.  
  662.    GENERAL_CLIP
  663.  
  664. #undef INCOUNT
  665. #undef INLIST
  666. #undef OUTLIST
  667. #undef INSIDE
  668. #undef COMPUTE_INTERSECTION
  669.  
  670.    /* 'OUTCOUNT' clipped vertices are now back in v[] */
  671.    return OUTCOUNT;
  672.  
  673. #undef GENERAL_CLIP
  674. #undef OUTCOUNT
  675. }
  676.  
  677.  
  678.  
  679.  
  680. /**********************************************************************/
  681. /*         Clipping against user-defined clipping planes.             */
  682. /**********************************************************************/
  683.  
  684.  
  685.  
  686. /*
  687.  * If the dot product of the eye coordinates of a vertex with the
  688.  * stored plane equation components is positive or zero, the vertex
  689.  * is in with respect to that clipping plane, otherwise it is out.
  690.  */
  691.  
  692.  
  693.  
  694. /*
  695.  * Clip a point against the user clipping planes.
  696.  * Input:  v - vertex-vector describing the point to clip.
  697.  * Return:  0 = point was clipped
  698.  *          1 = point not clipped
  699.  */
  700. GLuint gl_userclip_point( const GLfloat v[] )
  701. {
  702.    GLuint p;
  703.  
  704.    for (p=0;p<MAX_CLIP_PLANES;p++) {
  705.       if (CC.Transform.ClipEnabled[p]) {
  706.      GLfloat dot = v[0] * CC.Transform.ClipEquation[p][0]
  707.              + v[1] * CC.Transform.ClipEquation[p][1]
  708.              + v[2] * CC.Transform.ClipEquation[p][2]
  709.              + v[3] * CC.Transform.ClipEquation[p][3];
  710.          if (dot < 0.0F) {
  711.             return 0;
  712.          }
  713.       }
  714.    }
  715.  
  716.    return 1;
  717. }
  718.  
  719.  
  720. #define MAGIC_NUMBER -0.8e-03F
  721.  
  722.  
  723. /* Test if VB.Eye[J] is inside the clipping plane defined by A,B,C,D */
  724. #define INSIDE( J, A, B, C, D )                   \
  725.    ( (VB.Eye[J][0] * A + VB.Eye[J][1] * B            \
  726.     + VB.Eye[J][2] * C + VB.Eye[J][3] * D) >= MAGIC_NUMBER )
  727.  
  728.  
  729. /* Test if VB.Eye[J] is outside the clipping plane defined by A,B,C,D */
  730. #define OUTSIDE( J, A, B, C, D )                   \
  731.    ( (VB.Eye[J][0] * A + VB.Eye[J][1] * B            \
  732.     + VB.Eye[J][2] * C + VB.Eye[J][3] * D) < MAGIC_NUMBER )
  733.  
  734.  
  735. /*
  736.  * Clip a line against the user clipping planes.
  737.  * Input:  i, j - indexes into VB.V*[] of endpoints
  738.  * Output:  i, j - indexes into VB.V*[] of (possibly clipped) endpoints
  739.  * Return:  0 = line completely clipped
  740.  *          1 = line is visible
  741.  */
  742. GLuint gl_userclip_line( GLuint *i, GLuint *j )
  743. {
  744.    GLuint p, ii, jj;
  745.  
  746.    Space = EYE_SPACE;
  747.  
  748.    ii = *i;
  749.    jj = *j;
  750.  
  751.    for (p=0;p<MAX_CLIP_PLANES;p++) {
  752.       if (CC.Transform.ClipEnabled[p]) {
  753.      register GLfloat a, b, c, d;
  754.      a = CC.Transform.ClipEquation[p][0];
  755.      b = CC.Transform.ClipEquation[p][1];
  756.      c = CC.Transform.ClipEquation[p][2];
  757.      d = CC.Transform.ClipEquation[p][3];
  758.  
  759.          if (OUTSIDE( ii, a,b,c,d  )) {
  760.             if (OUTSIDE( jj, a,b,c,d )) {
  761.                /* ii and jj outside ==> quit */
  762.                return 0;
  763.             }
  764.             else {
  765.                /* ii is outside, jj is inside ==> clip */
  766.                GLfloat dx, dy, dz, dw, t, denom;
  767.                dx = VB.Eye[ii][0] - VB.Eye[jj][0];
  768.                dy = VB.Eye[ii][1] - VB.Eye[jj][1];
  769.                dz = VB.Eye[ii][2] - VB.Eye[jj][2];
  770.                dw = VB.Eye[ii][3] - VB.Eye[jj][3];
  771.            denom = dx*a + dy*b + dz*c + dw*d;
  772.            if (denom==0.0) {
  773.           t = 0.0;
  774.            }
  775.            else {
  776.           t = -(VB.Eye[jj][0]*a+VB.Eye[jj][1]*b
  777.                +VB.Eye[jj][2]*c+VB.Eye[jj][3]*d) / denom;
  778.                   if (t>1.0F)  t = 1.0F;
  779.            }
  780.            VB.Eye[VB.Free][0] = VB.Eye[jj][0] + t * dx;
  781.            VB.Eye[VB.Free][1] = VB.Eye[jj][1] + t * dy;
  782.            VB.Eye[VB.Free][2] = VB.Eye[jj][2] + t * dz;
  783.            VB.Eye[VB.Free][3] = VB.Eye[jj][3] + t * dw;
  784.  
  785.            /* Interpolate colors, indexes, and/or texture coords */
  786.            if (CC.ClipMask)  interpolate_aux( VB.Free, t, jj, ii );
  787.  
  788.            ii = VB.Free;
  789.            VB.Free++;
  790.            if (VB.Free==VB_SIZE)   VB.Free = 1;
  791.             }
  792.          }
  793.          else {
  794.             if (OUTSIDE( jj, a,b,c,d )) {
  795.                /* ii is inside, jj is outside ==> clip */
  796.                GLfloat dx, dy, dz, dw, t, denom;
  797.                dx = VB.Eye[jj][0] - VB.Eye[ii][0];
  798.                dy = VB.Eye[jj][1] - VB.Eye[ii][1];
  799.                dz = VB.Eye[jj][2] - VB.Eye[ii][2];
  800.                dw = VB.Eye[jj][3] - VB.Eye[ii][3];
  801.            denom = dx*a + dy*b + dz*c + dw*d;
  802.            if (denom==0.0) {
  803.           t = 0.0;
  804.            }
  805.            else {
  806.           t = -(VB.Eye[ii][0]*a+VB.Eye[ii][1]*b
  807.                +VB.Eye[ii][2]*c+VB.Eye[ii][3]*d) / denom;
  808.                   if (t>1.0F)  t = 1.0F;
  809.            }
  810.            VB.Eye[VB.Free][0] = VB.Eye[ii][0] + t * dx;
  811.            VB.Eye[VB.Free][1] = VB.Eye[ii][1] + t * dy;
  812.            VB.Eye[VB.Free][2] = VB.Eye[ii][2] + t * dz;
  813.            VB.Eye[VB.Free][3] = VB.Eye[ii][3] + t * dw;
  814.  
  815.            /* Interpolate colors, indexes, and/or texture coords */
  816.            if (CC.ClipMask)  interpolate_aux( VB.Free, t, ii, jj );
  817.  
  818.            jj = VB.Free;
  819.            VB.Free++;
  820.            if (VB.Free==VB_SIZE)   VB.Free = 1;
  821.             }
  822.             else {
  823.                /* ii and jj inside ==> do nothing */
  824.             }
  825.          }
  826.       }
  827.    }
  828.  
  829.    *i = ii;
  830.    *j = jj;
  831.    return 1;
  832. }
  833.  
  834.  
  835.  
  836.  
  837. /*
  838.  * Clip a polygon against the user clipping planes defined in eye coordinates.
  839.  * Input:  n - number of vertices.
  840.  *         vlist - list of vertices in input polygon.
  841.  * Output:  vlist - list of vertices in output polygon.
  842.  * Return:  number of vertices after clipping.
  843.  */
  844. GLuint gl_userclip_polygon( GLuint n, GLuint vlist[] )
  845. {
  846.    GLuint vlist2[VB_MAX];
  847.    GLuint *inlist, *outlist;
  848.    GLuint incount, outcount;
  849.    GLuint curri, currj;
  850.    GLuint previ, prevj;
  851.    GLuint p;
  852.  
  853.    Space = EYE_SPACE;
  854.  
  855.    /* initialize input vertex list */
  856.    incount = n;
  857.    inlist = vlist;
  858.    outlist = vlist2;
  859.  
  860.    for (p=0;p<MAX_CLIP_PLANES;p++) {
  861.       if (CC.Transform.ClipEnabled[p]) {
  862.      register float a = CC.Transform.ClipEquation[p][0];
  863.      register float b = CC.Transform.ClipEquation[p][1];
  864.      register float c = CC.Transform.ClipEquation[p][2];
  865.      register float d = CC.Transform.ClipEquation[p][3];
  866.  
  867.      if (incount<3)  return 0;
  868.  
  869.      /* initialize prev to be last in the input list */
  870.      previ = incount - 1;
  871.      prevj = inlist[previ];
  872.  
  873.          outcount = 0;
  874.  
  875.          for (curri=0;curri<incount;curri++) {
  876.         currj = inlist[curri];
  877.  
  878.             if (INSIDE(currj, a,b,c,d)) {
  879.                if (INSIDE(prevj, a,b,c,d)) {
  880.                   /* both verts are inside ==> copy current to outlist */
  881.           outlist[outcount++] = currj;
  882.                }
  883.                else {
  884.                   /* current is inside and previous is outside ==> clip */
  885.                   GLfloat dx, dy, dz, dw, t, denom;
  886.           /* compute t */
  887.           dx = VB.Eye[prevj][0] - VB.Eye[currj][0];
  888.           dy = VB.Eye[prevj][1] - VB.Eye[currj][1];
  889.           dz = VB.Eye[prevj][2] - VB.Eye[currj][2];
  890.           dw = VB.Eye[prevj][3] - VB.Eye[currj][3];
  891.           denom = dx*a + dy*b + dz*c + dw*d;
  892.           if (denom==0.0) {
  893.              t = 0.0;
  894.           }
  895.           else {
  896.              t = -(VB.Eye[currj][0]*a+VB.Eye[currj][1]*b
  897.                +VB.Eye[currj][2]*c+VB.Eye[currj][3]*d) / denom;
  898.                      if (t>1.0F) {
  899.                         /*printf("t1=%g\n", t);*/
  900.                         t = 1.0F;
  901.                      }
  902.           }
  903.           /* interpolate new vertex position */
  904.           VB.Eye[VB.Free][0] = VB.Eye[currj][0] + t*dx;
  905.           VB.Eye[VB.Free][1] = VB.Eye[currj][1] + t*dy;
  906.           VB.Eye[VB.Free][2] = VB.Eye[currj][2] + t*dz;
  907.           VB.Eye[VB.Free][3] = VB.Eye[currj][3] + t*dw;
  908.  
  909.           /* interpolate color, index, and/or texture coord */
  910.           if (CC.ClipMask) interpolate_aux( VB.Free, t, currj, prevj);
  911.           VB.Edgeflag[VB.Free] = VB.Edgeflag[prevj];
  912.  
  913.           /* output new vertex */
  914.           outlist[outcount++] = VB.Free;
  915.           VB.Free++;
  916.           if (VB.Free==VB_SIZE)   VB.Free = 1;
  917.           /* output current vertex */
  918.           outlist[outcount++] = currj;
  919.                }
  920.             }
  921.             else {
  922.                if (INSIDE(prevj, a,b,c,d)) {
  923.                   /* current is outside and previous is inside ==> clip */
  924.                   GLfloat dx, dy, dz, dw, t, denom;
  925.           /* compute t */
  926.                   dx = VB.Eye[currj][0]-VB.Eye[prevj][0];
  927.                   dy = VB.Eye[currj][1]-VB.Eye[prevj][1];
  928.                   dz = VB.Eye[currj][2]-VB.Eye[prevj][2];
  929.                   dw = VB.Eye[currj][3]-VB.Eye[prevj][3];
  930.           denom = dx*a + dy*b + dz*c + dw*d;
  931.           if (denom==0.0) {
  932.              t = 0.0;
  933.           }
  934.           else {
  935.              t = -(VB.Eye[prevj][0]*a+VB.Eye[prevj][1]*b
  936.                +VB.Eye[prevj][2]*c+VB.Eye[prevj][3]*d) / denom;
  937.                      if (t>1.0F) {
  938.                         /*printf("t2=%g\n", t);*/
  939.                         t = 1.0F;
  940.                      }
  941.           }
  942.           /* interpolate new vertex position */
  943.           VB.Eye[VB.Free][0] = VB.Eye[prevj][0] + t*dx;
  944.           VB.Eye[VB.Free][1] = VB.Eye[prevj][1] + t*dy;
  945.           VB.Eye[VB.Free][2] = VB.Eye[prevj][2] + t*dz;
  946.           VB.Eye[VB.Free][3] = VB.Eye[prevj][3] + t*dw;
  947.  
  948.           /* interpolate color, index, and/or texture coord */
  949.           if (CC.ClipMask) interpolate_aux( VB.Free, t, prevj, currj);
  950.           VB.Edgeflag[VB.Free] = VB.Edgeflag[prevj];
  951.  
  952.           /* output new vertex */
  953.           outlist[outcount++] = VB.Free;
  954.           VB.Free++;
  955.           if (VB.Free==VB_SIZE)   VB.Free = 1;
  956.            }
  957.                /* else  both verts are outside ==> do nothing */
  958.             }
  959.  
  960.         previ = curri;
  961.         prevj = currj;
  962.  
  963.          }  /* for i */
  964.  
  965.          /* swap inv and outv pointers */
  966.          {
  967.             GLuint *tmp;
  968.             tmp = inlist;
  969.             inlist = outlist;
  970.             outlist = tmp;
  971.             incount = outcount;
  972.          }
  973.  
  974.       } /* if */
  975.    } /* for p */
  976.  
  977.    /* outlist points to the list of vertices resulting from the last */
  978.    /* clipping.  If outlist == vlist2 then we have to copy the vertices */
  979.    /* back to vlist */
  980.    if (outlist!=vlist2) {
  981.       MEMCPY( vlist, vlist2, outcount * sizeof(GLuint) );
  982.    }
  983.  
  984.    return outcount;
  985. }
  986.  
  987.